using System;
using System.Data.Services.Client;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Common.Core;
using Common.Unity.Extensions;
using Microsoft.Practices.ObjectBuilder2;
using Guard=Microsoft.Practices.ObjectBuilder2.Guard;
using Common.Unity.Extensions.Entity.Extensions;

namespace Common.Unity.Extensions.Entity
{
	class ServicedEntityCreationPolicy : EntityContextCreationPolicyBase<DataServiceContext>
	{
		const string ResolveQueryName = "RetrieveResult";
		readonly static MethodInfo method = typeof(ServicedEntityCreationPolicy).GetMethod( ResolveQueryName, CommonBindingFlags.AllProperties );
		readonly string query;

		public ServicedEntityCreationPolicy( DataServiceContext serviceContext, IEntityCreator creator, string query ) : base( serviceContext, creator ?? new ServicedEntityCreator( serviceContext ) )
		{
			Guard.ArgumentNotNullOrEmpty( query, "query" );
			this.query = query;
		}

		string ResolveUri( IBuilderContext context )
		{
			var source = context.GetBuildSource();
			var result = source != null ? string.Format( new NamedTokenFormatter(), query, source ) : query;
			Debug.WriteLine( string.Format( "Resolved Query Uri = {0}", result ) );
			return result;
		}

		object RetrieveResult<ItemType>( Type elementType, string uri )
		{
			var requestUri = new Uri( string.Concat( EntityContext.BaseUri.ToString(), uri ) );
			var serviceQuery = EntityContext.Execute<ItemType>( requestUri );
			var result = elementType == typeof(ItemType) ? (object)serviceQuery.ToList().FirstOrDefault() : serviceQuery;
			return result;
		}

		protected override object RetrieveExistingEntity( IBuilderContext context )
		{
			Type type;
			if ( BuildKey.TryGetType( context.BuildKey, out type ) )
			{
				var elementType = ListHelper.ResolveElementType( type ) ?? type;
				var result = method.MakeGenericMethod( elementType ).Invoke( this, new object[] { type, ResolveUri( context ) } );
				return result;
			}
			return null;
		}
	}
}